package cn.jtcoding.utils;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @author jason.tang
 */

public final class FunctionUtils {
    /**
     * 快速映射集合
     * @param collection 集合
     * @param mapper     映射函数
     * @param <E>        源对象类型
     * @param <R>        目标对象类型
     * @return 目标结果集合
     */
    public static <E, R> List<R> map(Collection<E> collection, Function<E, R> mapper) {
        return collection.stream().map(mapper).collect(toList());
    }

    /**
     * 根据自定义条件过滤出对象
     * @param collection 集合
     * @param <E>        目标对象类型
     * @return 目标目标对象
     */
    public static <E> Function<Predicate<E>, Optional<E>> filterOutObject(Collection<E> collection) {
        return predicate -> collection.stream().filter(predicate).findFirst();
    }

    /**
     * 根据自定义条件过滤出集合
     * @param collection 集合
     * @param <E>        目标对象类型
     * @return 目标对象集合
     */
    public static <E> Function<Predicate<E>, Collection<E>> filterOutCollection(Collection<E> collection) {
        return predicate -> collection.stream().filter(predicate).collect(toList());
    }

    /**
     * 分组
     * @param collection 集合
     * @param mapper 映射函数
     * @param <E> 集合元素类型
     * @param <K> 目标map key类型
     * @return 集合
     */
    public static <E, K> Map<K, List<E>> groupBy(Collection<E> collection, Function<E, K> mapper) {
        return collection.stream().collect(Collectors.groupingBy(mapper));
    }

    /**
     * map排序
     * @param map 集合
     * @param <K> 目标map key类型
     * @param <V> 目标map value类型
     * @return 有序集合
     */
    public static <K, V> LinkedHashMap<K, V> sortMap(Map<K, V> map) {
        return map.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByKey(Comparator.comparing(Object::toString)))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        right(),
                        LinkedHashMap::new));

    }

    /**
     * list 转 有序map
     * @param collection 集合
     * @param mapper 映射函数
     * @param <E> 数据源集合
     * @param <K> key
     * @return 有序map
     */
    public static <E, K> LinkedHashMap<K, List<E>> sortMap(Collection<E> collection, Function<E, K> mapper) {
        return sortMap(groupBy(collection, mapper));
    }

    /**
     * 取左边
     * @param <T> 元素类型
     * @return 左边值
     */
    public static <T> BinaryOperator<T> left() {
        return (l, r) -> l;
    }

    /**
     * 取右边
     * @param <T> 元素类型
     * @return 右边值
     */
    public static <T> BinaryOperator<T> right() {
        return (l, r) -> r;
    }
}

